package be.cosic.credentialissuer.util;

import java.math.BigInteger;
import java.util.Random;
/**
 * Mathematical methods used during the signing process
 */
public class MathUtils {
	static Random random = new Random();
	/**
	 * Generate a Sophie Germain primer number. A Shophie Germain number p is obtained from another prime
	 * numer p' in this way: p = 2*p' +1. 
	 * @param numBytes Number of bytes of the demanded number
	 * @param certainty The numer will be prime with a probability 1/2^certainty
	 * @return A Sophie Germain number
	 */
	public static BigInteger GenerateSophieGermainPrime(int numBytes, int certainty) {
		int numBits = numBytes*8;
		for(;;) {
			BigInteger pp = new BigInteger(numBits,random);
			if (!pp.isProbablePrime(certainty)){
				continue;
			}
			else{
				pp=pp.multiply(BigInteger.valueOf(2));//p=pp*2
				pp=pp.add(BigInteger.valueOf(1));//p=pp*2+1
				if (pp.isProbablePrime(certainty)) return pp;
			}
		}
	}

	/**
	 * This method returns a quadratic residue generator.
	 * @param modulus Group of the generator
	 * @return QRn generator
	 */
	public static BigInteger GenerateQRnGenerator(BigInteger modulus) {

		BigInteger generator=GenerateRandomNumber(modulus);
		generator=generator.modPow(BigInteger.valueOf(2), modulus);
		return generator;
	}

	/**
	 * Method for creating a prime number
	 * @param range Range of the created number
	 * @return Prime number
	 */
	public static BigInteger GenerateRandomNumber(BigInteger range) {
		BigInteger num;
		for (;;){
			num = new BigInteger(range.bitLength(), random);
			if (num.compareTo(range)==-1) break;
		}
		return num;
	}

	/**
	 * Method for generating a prime number given its number of bits
	 * @param numBits Number of bits of the desired number
	 * @return Prime number
	 */
	public static BigInteger GenerateRandomNumber(int numBits) {
		BigInteger num;
		num = new BigInteger(numBits, random);
		return num;
	}
	
	/**
	 * This method returns an unsigned version of a given integer.
	 * @param a Integer to be unsigned
	 * @return Unsigned integer
	 */
	public static int unsignedInt(int a) {
		if (a < 0) {
			return a + 256;
		}
		return a;
	}
	/**
	 * This method returns the lower integer in a given pair
	 * @param a First integer
	 * @param b Second integer
	 * @return The lower integer.
	 */
	public static int min(int a, int b) {
		if (a < b) {
			return a;
		}
		return b;
	}
}
